home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / DTP / DTP_TEX / H219.ZIP / DVIPSSRC.ZIP / dvips / emspecia.c < prev    next >
C/C++ Source or Header  |  1993-02-11  |  36KB  |  1,479 lines

  1. /*
  2.  *   emspecial.c
  3.  *   This routine handles the emTeX special commands.
  4.  */
  5. #include "dvips.h" /* The copyright notice in that file is included too!*/
  6.  
  7. #include <ctype.h>
  8. extern int atoi();
  9. extern FILE *search();
  10. extern char *getenv();
  11. /*
  12.  *   These are the external routines called:
  13.  */
  14. /**/
  15. extern void hvpos() ;
  16. extern void cmdout() ;
  17. extern void mhexout() ;
  18. extern void nlcmdout() ;
  19. extern void newline() ;
  20. extern void floatout() ;
  21. extern void numout() ;
  22. extern void error() ;
  23. extern void specerror() ;
  24. extern char errbuf[] ;
  25. extern shalfword linepos;
  26. extern FILE *bitfile;
  27. extern int actualdpi ;
  28. extern int vactualdpi ;
  29. extern integer hh, vv;
  30. extern char *figpath ;
  31. extern int prettycolumn ;
  32. extern int quiet;
  33. extern Boolean disablecomments ;
  34.  
  35. #ifdef DEBUG
  36. extern integer debug_flag;
  37. #endif
  38.  
  39.  
  40. #ifdef EMTEX
  41. /* emtex specials, added by rjl */
  42.  
  43. #define EMMAX 1613 /* maximum number of emtex special points */
  44. #define TRUE 1
  45. #define FALSE 0
  46.  
  47. /*
  48.  *   We define these seek constants if they don't have their
  49.  *   values already defined.
  50.  */
  51. #ifndef SEEK_SET
  52. #define SEEK_SET (0)
  53. #endif
  54. #ifndef SEEK_END
  55. #define SEEK_END (2)
  56. #endif
  57.  
  58. struct empt {
  59.    shalfword point;
  60.    integer x, y;
  61. };
  62.  
  63. struct empt *empoints = NULL;
  64. boolean emused = FALSE;  /* true if em points used on this page */
  65. integer emx, emy;
  66.  
  67. struct emunit {
  68.    char *unit;
  69.    float factor;
  70. };
  71. struct emunit emtable[] = {
  72.   {"pt",72.27},
  73.   {"pc",72.27/12},
  74.   {"in",1.0},
  75.   {"bp",72.0},
  76.   {"cm",2.54},
  77.   {"mm",25.4},
  78.   {"dd",72.27/(1238/1157)},
  79.   {"cc",72.27/12/(1238/1157)},
  80.   {"sp",72.27*65536},
  81.   {"",0.0}
  82. };
  83.  
  84.  
  85. /* clear the empoints array if necessary */
  86. void
  87. emclear()
  88. {
  89. int i;
  90.    if (emused && empoints)
  91.       for (i=0; i<EMMAX; i++)
  92.          empoints[i].point = 0;
  93.    emused = FALSE ;
  94. }
  95.  
  96. /* put an empoint into the empoints array */
  97. struct empt *emptput(point, x, y)
  98. shalfword point;
  99. integer x, y;
  100. {
  101. int i, start;
  102.  
  103.    emused = TRUE;
  104.    start = point % EMMAX;
  105.    i = start;
  106.    while ( empoints[i].point != 0 ) {
  107.       if ( empoints[i].point == point )
  108.          break;
  109.       i++;
  110.       if (i >= EMMAX)
  111.          i = 0;
  112.       if (i == start) {
  113.      sprintf(errbuf,"!Too many em: special points");
  114.      specerror(errbuf);
  115.       }
  116.    }
  117.  
  118.    empoints[i].point = point;
  119.    empoints[i].x = x;
  120.    empoints[i].y = y;
  121.    return(&empoints[i]);
  122. }
  123.  
  124. /* get an empoint from the empoints array */
  125. struct empt *emptget(point)
  126. shalfword point;
  127. {
  128. int i, start;
  129.  
  130.    start = point % EMMAX;
  131.    i = start;
  132.    if (emused == TRUE)
  133.       while ( empoints[i].point != 0 ) {
  134.          if (empoints[i].point == point)
  135.             return(&empoints[i]);
  136.          i++;
  137.          if (i >= EMMAX)
  138.             i = 0;
  139.          if (i == start)
  140.             break;
  141.       }
  142.    sprintf(errbuf,"!em: point %d not defined",point);
  143.    specerror(errbuf);
  144.    return(NULL); /* never returns due to error */
  145. }
  146.  
  147.  
  148. /* convert width into dpi units */
  149. float emunits(width,unit)
  150. float width;
  151. char *unit;
  152. {
  153. struct emunit *p;
  154.     for (p=emtable; *(p->unit)!='\0'; p++) {
  155.        if (strcmp(p->unit,unit)==0)
  156.         return( width * actualdpi / p->factor );
  157.     }
  158.     return (-1.0); /* invalid unit */
  159. }
  160.  
  161. /* The main routine for \special{em:graph ...} called from dospecial.c */
  162. /* the line cut parameter is not supported (and is ignored) */
  163.  
  164. void emspecial(p)
  165. char *p ;
  166. {
  167. float emwidth, emheight;
  168. shalfword empoint1, empoint2;
  169. struct empt *empoint;
  170. char emunit[3];
  171. char emstr[80];
  172. char *emp;
  173. void emgraph();
  174.  
  175.         hvpos() ;
  176.     for (emp = p+3; *emp && isspace(*emp); emp++); /* skip blanks */
  177.     if (strncmp(emp, "linewidth", 9) == 0) {
  178.        /* code for linewidth */
  179.        for (emp = emp+9; *emp && isspace(*emp); emp++); /* skip blanks */
  180.        sscanf(emp, "%f%2s", &emwidth, emunit);
  181.        emwidth = emunits(emwidth,emunit);
  182.        if (emwidth!=-1.0) {
  183.           sprintf(emstr,"%.1f setlinewidth", emwidth);
  184.           cmdout(emstr);
  185. #ifdef DEBUG
  186.    if (dd(D_SPECIAL))
  187.       (void)fprintf(stderr, "em special: Linewidth set to %.1f dots\n", 
  188.         emwidth) ;
  189. #endif
  190.        } else {
  191.           sprintf(errbuf,"Unknown em: special width");
  192.           specerror(errbuf);
  193.        }
  194.     }
  195.         else if (strncmp(emp, "moveto", 6) == 0) {
  196. #ifdef DEBUG
  197.    if (dd(D_SPECIAL))
  198. #ifdef SHORTINT
  199.       (void)fprintf(stderr, "em special: moveto %ld,%ld\n", hh, vv);
  200. #else
  201.       (void)fprintf(stderr, "em special: moveto %d,%d\n", hh, vv);
  202. #endif
  203. #endif
  204.            emx = hh;
  205.            emy = vv;
  206.         }
  207.         else if (strncmp(emp, "lineto", 6) == 0) {
  208. #ifdef DEBUG
  209.    if (dd(D_SPECIAL))
  210. #ifdef SHORTINT
  211.       (void)fprintf(stderr, "em special: lineto %ld,%ld\n", hh, vv);
  212. #else
  213.       (void)fprintf(stderr, "em special: lineto %d,%d\n", hh, vv);
  214. #endif
  215. #endif
  216.        cmdout("np");
  217.        numout(emx);
  218.        numout(emy);
  219.        cmdout("a");
  220.        numout(hh);
  221.        numout(vv);
  222.        cmdout("li");
  223.        cmdout("st");
  224.            emx = hh;
  225.            emy = vv;
  226.         }
  227.     else if (strncmp(emp, "point", 5) == 0) {
  228.            if (empoints == NULL) {
  229.               empoints = 
  230.               (struct empt *)mymalloc((integer)EMMAX * sizeof(struct empt)) ;
  231.               emused = TRUE;
  232.               emclear();
  233.            }
  234.        for (emp = emp+5; *emp && isspace(*emp); emp++); /* skip blanks */
  235.            empoint1 = (shalfword)atoi(emp);
  236.            empoint = emptput(empoint1,hh,vv);
  237. #ifdef DEBUG
  238.    if (dd(D_SPECIAL))
  239. #ifdef SHORTINT
  240.       (void)fprintf(stderr, "em special: Point %d is %ld,%ld\n",
  241. #else
  242.       (void)fprintf(stderr, "em special: Point %d is %d,%d\n",
  243. #endif
  244.         empoint->point, empoint->x, empoint->y) ;
  245. #endif
  246.     }
  247.     else if (strncmp(emp, "line", 4) == 0) {
  248.        for (emp = emp+4; *emp && isspace(*emp); emp++); /* skip blanks */
  249.            empoint1 = (shalfword)atoi(emp);
  250.        for (; *emp && isdigit(*emp); emp++); /* skip point 1 */
  251.        if ( *emp && strchr("hvp",*emp)!=0 )
  252.           emp++;  /* skip line cut */
  253.        for (; *emp && isspace(*emp); emp++); /* skip blanks */
  254.        if ( *emp && (*emp==',') )
  255.           emp++; /*  skip comma separator */
  256.        for (; *emp && isspace(*emp); emp++); /* skip blanks */
  257.            empoint2 = (shalfword)atoi(emp);
  258.        for (; *emp && isdigit(*emp); emp++); /* skip point 2 */
  259.        if ( *emp && strchr("hvp",*emp)!=0 )
  260.           emp++;  /* skip line cut */
  261.        for (; *emp && isspace(*emp); emp++); /* skip blanks */
  262.        if ( *emp && (*emp==',') )
  263.           emp++; /*  skip comma separator */
  264.        emwidth = -1.0;
  265.        emunit[0]='\0';
  266.        sscanf(emp, "%f%2s", &emwidth, emunit);
  267.        emwidth = emunits(emwidth,emunit);
  268. #ifdef DEBUG
  269.    if (dd(D_SPECIAL))
  270.       (void)fprintf(stderr, "em special: Line from point %d to point %d\n",
  271.         empoint1, empoint2) ;
  272. #endif
  273.        cmdout("np");
  274.        if (emwidth!=-1.0) {
  275. #ifdef DEBUG
  276.    if (dd(D_SPECIAL))
  277.    (void)fprintf(stderr,"em special: Linewidth temporarily set to %.1f dots\n", 
  278.         emwidth) ;
  279. #endif
  280.            strcpy(emstr,"currentlinewidth");
  281.            cmdout(emstr);
  282.             sprintf(emstr,"%.1f setlinewidth", emwidth);
  283.             cmdout(emstr);
  284.        }
  285.            empoint = emptget(empoint1);
  286.        numout(empoint->x);
  287.        numout(empoint->y);
  288.        cmdout("a");
  289.            empoint = emptget(empoint2);
  290.        numout(empoint->x);
  291.        numout(empoint->y);
  292.        cmdout("li");
  293.        cmdout("st");
  294.        if (emwidth!=-1.0) {
  295.            strcpy(emstr,"setlinewidth");
  296.            cmdout(emstr);
  297.        }
  298.     }
  299.     else if (strncmp(emp, "message", 7) == 0) {
  300.            (void)fprintf(stderr, "em message: %s\n", emp+7) ;
  301.     }
  302.     else if (strncmp(emp, "graph", 5) == 0) {
  303.        int i;
  304.        for (emp = emp+5; *emp && isspace(*emp); emp++); /* skip blanks */
  305.        for (i=0; *emp && !isspace(*emp) && !(*emp==',') ; emp++)
  306.           emstr[i++] = *emp; /* copy filename */
  307.        emstr[i] = '\0';
  308.        /* now get optional width and height */
  309.        emwidth = emheight = -1.0;    /* no dimension is <= 0 */
  310.        for (; *emp && ( isspace(*emp) || (*emp==',') ); emp++)
  311.           ;  /* skip blanks and comma */
  312.        if (*emp) {
  313.           sscanf(emp, "%f%2s", &emwidth, emunit); /* read width */
  314.           emwidth = emunits(emwidth,emunit); /* convert to pixels */
  315.           for (; *emp && ( isdigit(*emp) || isalpha(*emp) ); emp++)
  316.              ; /* skip width dimension */
  317.           for (; *emp && ( isspace(*emp) || (*emp==',') ); emp++)
  318.              ;  /* skip blanks and comma */
  319.           if (*emp) {
  320.              sscanf(emp, "%f%2s", &emheight, emunit); /* read height */
  321.              emheight = emunits(emheight,emunit)*vactualdpi/actualdpi;
  322.           }
  323.        }
  324.        if (emstr[0]) {
  325.           emgraph(emstr,emwidth,emheight);
  326.        }
  327.        else {
  328.               (void)fprintf(stderr, "em:graph: no file given\n") ;
  329.        }
  330.     }
  331.     else {
  332.            sprintf(errbuf, 
  333.           "Unknown em: command (%s) in \\special will be ignored", p);
  334.            specerror(errbuf) ;
  335.     }
  336.     return;
  337.    }
  338.  
  339.  
  340. /* em:graph routines */
  341.  
  342. /* The graphics routines currently decode 3 types of IBM-PC based graphics   */
  343. /* files: .pcx, .bmp, .msp. The information on the formats has occasionally  */
  344. /* been sketchy, and subject to interpretation. I have attempted to implement*/
  345. /* these routines to correctly decode the graphics file types mentioned.     */
  346. /* The compressed .bmp file type has not been tested fully due to a lack of  */
  347. /* test files.                                                               */
  348. /*                                                                           */
  349. /* The method of reading in the headers of the binary files is ungainly, but */
  350. /* portable. Failure to use a byte by byte read and convert method will      */
  351. /* result in portability problems. Specifically there is no requirement that */
  352. /* elements of a C structure be contiguous, only that they have an ascending */
  353. /* order of addresses.                                                       */
  354. /*                                                                           */
  355. /* The current implementations of the graphics format to postscript          */
  356. /* conversion are not the most efficient possible. Specifically: color       */
  357. /* formats are converted to RGB ratios prior to using a simple thresholding  */
  358. /* method to determine if the postscript bit is to be set. The thresholding  */
  359. /* method is compabible with that used in emtex's drivers.                   */
  360. /*                                                                           */
  361. /* Please send bug reports relating to the em:graph routines to:             */
  362. /*                maurice@bruce.cs.monash.edu.au                             */
  363. /*                                                                           */
  364. /* My thanks to Russell Lang for his assistance with the implementation of   */
  365. /* these routines in a manner compatible with dvips and for the optimization */
  366. /* of some routines.                                                         */
  367. /*                                                                           */
  368. /*                                                   Maurice Castro          */
  369. /*                                                   8 Oct 92                */
  370.  
  371. /* Routines to read binary numbers from IBM PC file types */
  372. integer readinteger(f)
  373. FILE *f;
  374. {
  375.    integer i;
  376.    int r;
  377.  
  378.    i = 0;
  379.    for (r = 0; r < 4; r++)
  380.    {
  381.       i = i |  ( ((integer) fgetc(f)) << (8*r) );
  382.    }
  383.    return(i);
  384. }
  385.  
  386. halfword readhalfword(f)
  387. FILE *f;
  388. {
  389.    halfword i;
  390.    int r;
  391.  
  392.    i = 0;
  393.    for (r = 0; r < 2; r++)
  394.    {
  395.      i = i |  ( ((halfword) fgetc(f)) << (8*r) );
  396.    }
  397.    return(i);
  398. }
  399.  
  400. #define readquarterword(f) ((unsigned char)fgetc(f))
  401. #define tobyte(x) ((x/8) + (x%8 ? 1 : 0))
  402.  
  403. /* These routines will decode PCX files produced by Microsoft 
  404.  * Windows Paint.  Other programs may not produce files which
  405.  * will be successfully decoded, most notably version 1.xx of
  406.  * PC Paint. */
  407.  
  408. /*
  409.  *   Type declarations.  integer must be a 32-bit signed; shalfword must
  410.  *   be a sixteen-bit signed; halfword must be a sixteen-bit unsigned;
  411.  *   quarterword must be an eight-bit unsigned.
  412.  */
  413. typedef struct 
  414. {
  415.     quarterword man;
  416.     quarterword ver;
  417.     quarterword enc;
  418.     quarterword bitperpix;
  419.     halfword xmin;
  420.     halfword ymin;
  421.     halfword xmax;
  422.     halfword ymax;
  423.     halfword hres;
  424.     halfword vres;
  425.     quarterword pal[48];
  426.     quarterword reserved;
  427.     quarterword colorplanes;
  428.     halfword byteperline;
  429.     halfword paltype;
  430.     quarterword fill[58];
  431. } PCXHEAD; 
  432.  
  433. int PCXreadhead(pcxf, pcxh)
  434. FILE *pcxf;
  435. PCXHEAD *pcxh;
  436. {
  437.     pcxh->man = readquarterword(pcxf);
  438.     pcxh->ver = readquarterword(pcxf);
  439.     pcxh->enc = readquarterword(pcxf);
  440.     pcxh->bitperpix = readquarterword(pcxf);
  441.     pcxh->xmin = readhalfword(pcxf);
  442.     pcxh->ymin = readhalfword(pcxf);
  443.     pcxh->xmax = readhalfword(pcxf);
  444.     pcxh->ymax = readhalfword(pcxf);
  445.     pcxh->hres = readhalfword(pcxf);
  446.     pcxh->vres = readhalfword(pcxf);
  447.     fread(pcxh->pal, 1, 48, pcxf);
  448.     pcxh->reserved = readquarterword(pcxf);
  449.     pcxh->colorplanes = readquarterword(pcxf);
  450.     pcxh->byteperline = readhalfword(pcxf);
  451.     pcxh->paltype = readhalfword(pcxf);
  452.     fread(pcxh->fill, 1, 58, pcxf);
  453.  
  454.     if (feof(pcxf))
  455.         return(0);                /* fail */
  456.     if (pcxh->man != 0x0a)
  457.         return(0);                /* fail */
  458.     if (pcxh->enc != 0x1)
  459.         return(0);                /* fail */
  460.     return(1);                    /* success */
  461.     }
  462.  
  463. int PCXreadline(pcxf, pcxbuf, byteperline)
  464. FILE *pcxf;
  465. unsigned char *pcxbuf;
  466. unsigned int byteperline;
  467. {
  468.     int n;
  469.     int c;
  470.     int i;
  471.  
  472.     n = 0;
  473.     memset(pcxbuf,0,byteperline);
  474.     do {
  475.         c = fgetc(pcxf);
  476.         if ((c & 0xc0) == 0xc0) {
  477.             i = c & 0x3f;
  478.             c = fgetc(pcxf) & 0xff;
  479.             while ((i--) && (n < byteperline)) pcxbuf[n++] = c;
  480.         }
  481.         else {
  482.             pcxbuf[n++] = c & 0xff;
  483.         }
  484.     } while (n < byteperline);
  485.     if (c==EOF) n=0;
  486.     return(n);
  487. }
  488.  
  489. void PCXgetpalette(pcxf, pcxh, r, g, b)
  490. FILE *pcxf;
  491. PCXHEAD *pcxh;
  492. unsigned char r[256];
  493. unsigned char g[256];
  494. unsigned char b[256];
  495. {
  496.     int i;
  497.  
  498.     /* clear palette */
  499.     for (i=0; i < 256; i++) {
  500.         r[i] = 0;
  501.         g[i] = 0;
  502.         b[i] = 0;
  503.     }
  504.  
  505.     switch (pcxh->ver) {
  506.         case 0:
  507.             /* version 2.5 of PC Paint Brush */
  508.             for (i=0; i < 16; i++) {
  509.                 r[i] = pcxh->pal[i*3];
  510.                 g[i] = pcxh->pal[i*3+1];
  511.                 b[i] = pcxh->pal[i*3+2];
  512.             }
  513.             break;
  514.         case 2:
  515.             /* version 2.8 of PC Paint Brush with valid Palette */
  516.             for (i=0; i < 16; i++) {
  517.                 r[i] = pcxh->pal[i*3];
  518.                 g[i] = pcxh->pal[i*3+1];
  519.                 b[i] = pcxh->pal[i*3+2];
  520.             }
  521.             break;
  522.         case 3:
  523.             /* version 2.8 of PC Paint Brush with no valid Palette */
  524.             /* either mono or default */
  525.  
  526.             if (pcxh->colorplanes != 1) {
  527.                 /* Color default palette - should be checked */
  528.                 r[0] = 0x00;        g[0] = 0x00;        b[0] = 0x00;
  529.                 r[1] = 0x80;        g[1] = 0x00;         b[1] = 0x00;
  530.                 r[2] = 0x00;         g[2] = 0x80;         b[2] = 0x00;
  531.                 r[3] = 0x80;        g[3] = 0x80;         b[3] = 0x00;
  532.                 r[4] = 0x00;        g[4] = 0x00;         b[4] = 0x80;
  533.                 r[5] = 0x80;        g[5] = 0x00;         b[5] = 0x80;
  534.                 r[6] = 0x00;        g[6] = 0x80;         b[6] = 0x80;
  535.                 r[7] = 0x80;        g[7] = 0x80;         b[7] = 0x80;
  536.                 r[8] = 0xc0;        g[8] = 0xc0;        b[8] = 0xc0;
  537.                 r[9] = 0xff;        g[9] = 0x00;         b[9] = 0x00;
  538.                 r[10] = 0x00;         g[10] = 0xff;         b[10] = 0x00;
  539.                 r[11] = 0xff;         g[11] = 0xff;         b[11] = 0x00;
  540.                 r[12] = 0x00;         g[12] = 0x00;         b[12] = 0xff;
  541.                 r[13] = 0xff;         g[13] = 0x00;         b[13] = 0xff;
  542.                 r[14] = 0x00;         g[14] = 0xff;         b[14] = 0xff;
  543.                 r[15] = 0xff;         g[15] = 0xff;         b[15] = 0xff;
  544.             }
  545.             else {
  546.                 /* mono palette */
  547.                 r[0] = 0x00;        g[0] = 0x00;        b[0] = 0x00;
  548.                 r[1] = 0xff;        g[1] = 0xff;         b[1] = 0xff;
  549.             }
  550.             break;
  551.         case 5:
  552.         default:
  553.             /* version 3.0 of PC Paint Brush or Better */
  554.             fseek(pcxf, -769L, SEEK_END);
  555.             /* if signature byte is correct then read the palette */
  556.             /* otherwise copy the existing palette */
  557.             if (fgetc(pcxf) == 12) {
  558.                 for (i=0; i < 256; i++) {
  559.                     r[i] = fgetc(pcxf);
  560.                     g[i] = fgetc(pcxf);
  561.                     b[i] = fgetc(pcxf);
  562.                 }
  563.             }
  564.             else {
  565.                 for (i=0; i < 16; i++) {
  566.                     r[i] = pcxh->pal[i*3];
  567.                     g[i] = pcxh->pal[i*3+1];
  568.                     b[i] = pcxh->pal[i*3+2];
  569.                 }
  570.             }
  571.             break;
  572.     }
  573. }
  574.  
  575. extern void mhexout() ;
  576.  
  577. void PCXshowpicture(pcxf, wide, high, bytes, cp, bp, r, g, b)
  578. FILE *pcxf;
  579. int wide;
  580. int high;
  581. int bytes;
  582. int cp;
  583. int bp;
  584. unsigned char r[256];
  585. unsigned char g[256];
  586. unsigned char b[256];
  587. {
  588.     int x;
  589.     int y;
  590.     int c;
  591.     unsigned char *rowa[4];                /* row array */
  592.     unsigned char *row;
  593.     int p;
  594.     unsigned char *pshexa;
  595.     int xdiv, xmod, xbit;
  596.     int width;
  597.     int bytewidth;
  598.  
  599.     bytewidth = tobyte(wide);
  600.     width = bytewidth * 8;
  601.  
  602.     /* output the postscript image size preamble */
  603.     cmdout("/picstr ");
  604.     numout((integer)tobyte(wide));
  605.     cmdout("string def");
  606.  
  607.     numout((integer)width);
  608.     numout((integer)high);
  609.     numout((integer)1);
  610.     newline();
  611.  
  612.     cmdout("[");
  613.     numout((integer)width);
  614.     numout((integer)0);
  615.     numout((integer)0);
  616.     numout((integer)-high);
  617.     numout((integer)0);
  618.     numout((integer)0);
  619.     cmdout("]");
  620.  
  621.     nlcmdout("{currentfile picstr readhexstring pop} image");
  622.  
  623.     /* allocate the postscript hex output array */
  624.     pshexa = (unsigned char *) mymalloc((integer)bytewidth);
  625.  
  626.     /* make sure that you start at the right point in the file */
  627.     fseek(pcxf, (long) sizeof(PCXHEAD), SEEK_SET);
  628.  
  629.     /* malloc the lines */
  630.     row = (unsigned char *) mymalloc((integer)bytes * cp);
  631.     for (c = 0; c < cp; c++)
  632.         rowa[c] = row + bytes*c;
  633.  
  634.     for (y = 0; y < high; y++) {
  635.         /* clear the postscript hex array */
  636.         memset(pshexa,0xff,bytewidth);
  637.  
  638.         /* read in all the color planes for a row of pixels */
  639.         PCXreadline(pcxf, rowa[0], bytes*cp);
  640.  
  641.         /* process each pixel */
  642.         for (x = 0; x < wide; x++) {
  643.             /* build up the pixel value from color plane entries */
  644.             p = 0;
  645.             xdiv = x>>3;
  646.             xmod = 7 - (x&7);
  647.             xbit = 1 << xmod;
  648.             switch(bp) {
  649.                 case 1: 
  650.                     for (c = 0; c < cp; c++) {
  651.                         row = rowa[c];
  652.                         p |= ( (unsigned)(row[xdiv] & xbit) >> xmod ) << c;
  653.                     }
  654.                     break;
  655.                 case 4:  /* untested - most programs use 1 bit/pixel, 4 planes */
  656.                     row = rowa[0]; /* assume single plane */
  657.                     p = ( x & 1 ? row[xdiv] : row[xdiv]>>4 ) & 0x0f;
  658.                     break;
  659.                 case 8:
  660.                     row = rowa[0]; /* assume single plane */
  661.                     p = (unsigned) (row[x]);
  662.                     break;
  663.                 default: 
  664.                     fprintf(stderr, "em:graph: Unable to Decode this PCX file\n");
  665.                     return;
  666.             }
  667.             if ((r[p] < 0xff) || (g[p] < 0xff) || (b[p] < 0xff))
  668.                 pshexa[xdiv] &= (~xbit);
  669.             else
  670.                 pshexa[xdiv] |= xbit;
  671.         }
  672.         newline();
  673.         mhexout(pshexa,(long)bytewidth);
  674.     }
  675.     free(pshexa);
  676.     free(rowa[0]);
  677. }
  678.  
  679. void imagehead(filename,wide,high,emwidth,emheight)
  680. char filename[];
  681. int wide, high;
  682. float emwidth, emheight;    /* dimension in pixels */
  683. {
  684.     if (!quiet) {
  685.         if (strlen(filename) + prettycolumn > STDOUTSIZE) {
  686.         fprintf(stderr,"\n");
  687.         prettycolumn = 0;
  688.         }
  689.         (void)fprintf(stderr,"<%s",filename);
  690.         (void)fflush(stderr);
  691.         prettycolumn += 2+strlen(filename);
  692.     }
  693.     hvpos();
  694.     nlcmdout("@beginspecial @setspecial") ;
  695.     if (!disablecomments) {
  696.         cmdout("%%BeginDocument: em:graph");
  697.         cmdout(filename);
  698.         newline();
  699.     }
  700.     /* set the image size */
  701.     if (emwidth <= 0.0)  emwidth = (float)wide;
  702.     if (emheight <= 0.0)  emheight = (float)high;
  703.     floatout(emwidth*72/actualdpi);
  704.     floatout(emheight*72/vactualdpi);
  705.     newline();
  706.     cmdout("scale");
  707. #ifdef DEBUG
  708.     if (dd(D_SPECIAL)) {
  709.       (void)fprintf(stderr, 
  710.         "\nem:graph: %s width  %d pixels scaled to %.1f pixels\n",
  711.         filename, wide, emwidth);
  712.       (void)fprintf(stderr, 
  713.         "em:graph: %s height %d pixels scaled to %.1f pixels\n",
  714.         filename, high, emheight);
  715.        }
  716. #endif
  717. }
  718.  
  719. void imagetail()
  720. {
  721.     if (!disablecomments) {
  722.         (void)fprintf(bitfile, "%%%%EndDocument\n") ;
  723.         linepos = 0;
  724.     }
  725.     nlcmdout("@endspecial") ;
  726.     if (!quiet) {
  727.         (void)fprintf(stderr,">");
  728.         (void)fflush(stderr);
  729.     }
  730. }
  731.  
  732. void pcxgraph(pcxf,filename,emwidth,emheight)
  733. FILE *pcxf;
  734. char filename[];
  735. float emwidth, emheight;    /* dimension in pixels */
  736. {
  737.     PCXHEAD pcxh;
  738.     unsigned char red[256];
  739.     unsigned char green[256];
  740.     unsigned char blue[256];
  741.     int wide;
  742.     int high;
  743.     int bytes;
  744.     int cp;
  745.     int bpp;
  746.  
  747.     if (!PCXreadhead(pcxf, &pcxh)) {
  748.         sprintf(errbuf,"em:graph: Unable to Read Valid PCX Header");
  749.         specerror(errbuf);
  750.     }
  751.     PCXgetpalette(pcxf, &pcxh, red, green, blue);
  752.  
  753.     /* picture size calculation */
  754.     wide = (pcxh.xmax - pcxh.xmin) + 1;
  755.     high = (pcxh.ymax - pcxh.ymin) + 1;
  756.     bytes = pcxh.byteperline;
  757.     cp = pcxh.colorplanes;
  758.     bpp = pcxh.bitperpix;
  759.  
  760.     imagehead(filename,wide,high,emwidth,emheight);
  761.     PCXshowpicture(pcxf, wide, high, bytes, cp, bpp, red, green, blue);
  762.     imagetail();
  763. }
  764.  
  765. /* Microsoft Paint routines */
  766. struct wpnt_1 {
  767.     quarterword id[4];
  768.     halfword width;
  769.     halfword high;
  770.     halfword x_asp;
  771.     halfword y_asp;
  772.     halfword x_asp_prn;
  773.     halfword y_asp_prn;
  774.     halfword width_prn;
  775.     halfword high_prn;
  776.     integer chk_sum;
  777.     halfword chk_head;
  778. };
  779.  
  780. #define WPAINT_1 1
  781. #define WPAINT_2 2
  782.  
  783. void MSP_2_ps(f, wide, high)
  784. FILE *f;
  785. int wide;
  786. int high;
  787. {
  788.     char *line;
  789.     char *l;
  790.     int i;
  791.     int j;
  792.     unsigned char a, b, c;
  793.     int d;
  794.     int width;
  795.     halfword *linelen;
  796.  
  797.     /* an undocumented format - based on a type of run length encoding    */
  798.     /* the format is made up of a list of line lengths, followed by a set */
  799.     /* of lines. Each line is made up of 2 types of entries:              */
  800.     /*     1) A 3 term entry (0 a b): the byte b is repeated a times     */
  801.     /*    2) A variable length entry (a xxxx....xxxx): a bytes are read */
  802.     /*       from the file.                                             */
  803.     /* These entries are combined to build up a line                      */
  804.  
  805.     width = tobyte(wide)*8;
  806.  
  807.     /* output the postscript image size preamble */
  808.     cmdout("/picstr");
  809.     numout((integer)tobyte(wide));
  810.     cmdout("string def");
  811.  
  812.     numout((integer)width);
  813.     numout((integer)high);
  814.     numout((integer)1);
  815.  
  816.     cmdout("[");
  817.     numout((integer)width);
  818.     numout((integer)0);
  819.     numout((integer)0);
  820.     numout((integer)-high);
  821.     numout((integer)0);
  822.     numout((integer)0);
  823.     cmdout("]");
  824.  
  825.     nlcmdout("{currentfile picstr readhexstring pop} image");
  826.  
  827.     fseek(f, 32, SEEK_SET);
  828.  
  829.     /* read in the table of line lengths */    
  830.     linelen = (halfword *) mymalloc((integer)sizeof(halfword) * high);
  831.     for (i = 0; i < high; i++) {
  832.         linelen[i] = readhalfword(f);
  833.         if (feof(f))
  834.             return;
  835.     }
  836.  
  837.     line = (char *) mymalloc((integer)tobyte(wide));
  838.     for (i = 0; i < high; i++) {
  839.         memset(line, 0xff, tobyte(wide));
  840.         l = line;
  841.         if (linelen[i] != 0) {
  842.             d = linelen[i];
  843.             while (d) {
  844.                 a = fgetc(f);
  845.                 d--;
  846.                 if (a == 0) {
  847.                     b = fgetc(f);
  848.                     c = fgetc(f);
  849.                     d -= 2;
  850.                     for (j = 0; j < b; j++)
  851.                         *l++ = c;
  852.                 }
  853.                 else {
  854.                     for (j = 0; j < a; j++)
  855.                         *l++ = fgetc(f);
  856.                     d -= j;
  857.                 }
  858.             }
  859.         }
  860.         newline();
  861.         mhexout(line,(long)tobyte(wide));
  862.     }
  863.     free(linelen);
  864.     free(line);
  865. }
  866.  
  867. void MSP_1_ps(f, wide, high)
  868. FILE *f;
  869. int wide;
  870. int high;
  871. {
  872.     char *line;
  873.     int i;
  874.     int width;
  875.  
  876.     width = tobyte(wide)*8;
  877.     /* an partly documented format - see The PC Sourcebook                */
  878.     /* the format is made up of a simple bitmap.                          */
  879.  
  880.     /* output the postscript image size preamble */
  881.     cmdout("/picstr");
  882.     numout((integer)tobyte(wide));
  883.     cmdout("string def");
  884.  
  885.     numout((integer)width);
  886.     numout((integer)high);
  887.     numout((integer)1);
  888.  
  889.     cmdout("[");
  890.     numout((integer)width);
  891.     numout((integer)0);
  892.     numout((integer)0);
  893.     numout((integer)-high);
  894.     numout((integer)0);
  895.     numout((integer)0);
  896.     cmdout("]");
  897.  
  898.     nlcmdout("{currentfile picstr readhexstring pop} image");
  899.  
  900.     fseek(f, 32, SEEK_SET);
  901.  
  902.     line = (char *) mymalloc((integer)tobyte(wide));
  903.     for (i = 0; i < high; i++) {
  904.         fread(line, 1, tobyte(wide), f);
  905.         newline();
  906.         mhexout(line,(long)tobyte(wide));
  907.     }
  908.     free(line);
  909. }
  910.  
  911.  
  912. void mspgraph(f,filename,emwidth,emheight)
  913. FILE *f;
  914. char filename[];
  915. float emwidth, emheight;    /* dimension in pixels */
  916. {
  917.     struct wpnt_1 head;
  918.     int paint_type = 0;
  919.  
  920.         /* read the header of the file and figure out what it is */
  921.     fread(head.id, 1, 4, f);
  922.     head.width = readhalfword(f); 
  923.     head.high = readhalfword(f); 
  924.     head.x_asp = readhalfword(f); 
  925.     head.y_asp = readhalfword(f); 
  926.     head.x_asp_prn = readhalfword(f); 
  927.     head.y_asp_prn = readhalfword(f); 
  928.     head.width_prn = readhalfword(f); 
  929.     head.high_prn = readhalfword(f); 
  930.     head.chk_sum = readinteger(f); 
  931.     head.chk_head = readhalfword(f); 
  932.  
  933.     if (feof(f)) {
  934.         fprintf(stderr, "em:graph: Unable to Read Valid MSP Header\n");
  935.         return;
  936.     }
  937.         
  938.         /* check the id bytes */
  939.     if (!memcmp(head.id, "DanM", 4))
  940.             paint_type = WPAINT_1;
  941.     if (!memcmp(head.id, "LinS", 4))
  942.         paint_type = WPAINT_2;
  943.  
  944.  
  945.     imagehead(filename,head.width,head.high,emwidth,emheight);
  946.     switch (paint_type) {
  947.         case WPAINT_1:
  948.                     MSP_1_ps(f, head.width, head.high);
  949.             break;
  950.                 case WPAINT_2:
  951.                     MSP_2_ps(f, head.width, head.high);
  952.             break;
  953.         default:
  954.             sprintf(errbuf, "em:graph: Unknown MSP File Type");
  955.             specerror(errbuf);
  956.     }
  957.     imagetail() ;
  958. }
  959.  
  960. /* ------------------------------------------------------------------------ */
  961. /* .BMP file structures */
  962. struct rgbquad {
  963.     char blue;
  964.     char green;
  965.     char red;
  966.     char res;
  967. };
  968.  
  969. struct bitmapinfoheader {
  970.     integer size;
  971.     integer width;
  972.     integer height;
  973.     halfword planes;            /* must be set to 1 */
  974.     halfword bitcount;            /* 1, 4, 8 or 24 */
  975.     integer compression;
  976.     integer sizeimage;
  977.     integer xpelspermeter;
  978.     integer ypelspermeter;
  979.     integer clrused;
  980.     integer clrimportant;
  981. };
  982.  
  983. /* constants for the compression field */
  984. #define RGB 0L
  985. #define RLE8 1L
  986. #define RLE4 2L
  987.  
  988. struct bitmapfileheader {
  989.     char type[2];
  990.     integer size;
  991.     halfword reserved1;
  992.     halfword reserved2;
  993.     integer offbits;
  994. };
  995.  
  996. void rgbread(f, w, b, s)
  997. FILE *f;
  998. int b;
  999. int w;
  1000. char *s;
  1001. {
  1002.     int i;
  1003.  
  1004.     /* set the line to white */
  1005.     memset(s, 0xff, ((w*b)/8)+1); 
  1006.  
  1007.     /* read in all the full bytes */
  1008.     for (i = 0; i < (w * b) / 8; i++)
  1009.         *s++ = fgetc(f);
  1010.  
  1011.     /* read in a partly filled byte */
  1012.     if ((w * b) % 8) {
  1013.         i++;
  1014.         *s++ = fgetc(f);
  1015.     }
  1016.  
  1017.     /* check that we are on a 32 bit boundary; otherwise align */
  1018.     while (i % 4 != 0) {
  1019.         fgetc(f);
  1020.         i++;
  1021.     }
  1022. }
  1023.  
  1024. unsigned rle_dx = 0;    /* delta command horizontal offset */
  1025. unsigned rle_dy = 0;    /* delta command vertical offset */
  1026.  
  1027. /* checked against output from Borland Resource Workshop */
  1028. void rle4read(f, w, b, s)
  1029. FILE *f;
  1030. int b;
  1031. int w;
  1032. char *s;
  1033. {
  1034.     int i;
  1035.     int limit;
  1036.     int ch;
  1037.     unsigned cnt;
  1038.     int hi;
  1039.  
  1040.     limit = (w*b)/8;
  1041.     i = 0;
  1042.     hi = TRUE;
  1043.     /* set the line to white */
  1044.     memset(s, 0xff, limit+1); 
  1045.  
  1046.     if (rle_dy) {
  1047.         rle_dy--;
  1048.         return;
  1049.     }
  1050.  
  1051.     if (rle_dx) {
  1052.         for ( ; rle_dx>1; rle_dx-=2) {
  1053.         s++;
  1054.         i++;
  1055.         }
  1056.         if (rle_dx)
  1057.             hi = FALSE;
  1058.     }
  1059.  
  1060.     while (i<=limit) {
  1061.         cnt = fgetc(f);
  1062.         ch  = fgetc(f);
  1063.         if (cnt == 0) { /* special operation */
  1064.         switch(ch) {
  1065.             case 0:    /* EOL */
  1066.             return;    /* this is our way out */
  1067.             case 1:    /* End of Bitmap */
  1068.                 return;
  1069.             case 2:    /* Delta */  /* untested */
  1070.             rle_dx = fgetc(f) + i*2 + (hi ? 1 : 0);
  1071.             rle_dy = fgetc(f);
  1072.             return;
  1073.             default:    /* next cnt bytes are absolute */
  1074.                 /* must be aligned on word boundary */
  1075.             if (!hi)
  1076.                 fprintf(stderr,"em:graph: RLE4 absolute is not byte aligned\n");
  1077.             for (cnt = ch; cnt>0 && i<=limit; cnt-=2) {
  1078.                     i++;
  1079.                 *s++ = fgetc(f);
  1080.             }
  1081.             if (ch % 4)    /* word align file */
  1082.                 (void)fgetc(f);
  1083.           }
  1084.         }
  1085.         else {   /* cnt is repeat count */
  1086.         if (!hi) {   /* we are about to place the low 4 bits */
  1087.             ch = ((ch>>4)&0x0f) | ((ch<<4)&0xf0); /* swap order */
  1088.             i++;
  1089.             *s++ = (*s & 0xf0) | (ch & 0x0f);
  1090.             hi = TRUE;
  1091.             cnt--;
  1092.         }
  1093.         /* we are about to place the high 4 bits */
  1094.         for ( ; cnt>1 && i<=limit ; cnt-=2) { /* place the whole bytes */
  1095.             i++;
  1096.             *s++ = ch;
  1097.             }
  1098.         if (cnt) { /* place the partial byte */
  1099.             *s = (*s & 0x0f) | (ch & 0xf0);
  1100.             hi = FALSE;
  1101.         }
  1102.         }
  1103.       }
  1104. }
  1105.   
  1106. /* untested */
  1107. void rle8read(f, w, b, s)
  1108. FILE *f;
  1109. int b;
  1110. int w;
  1111. char *s;
  1112. {
  1113.     int i;
  1114.     int limit;
  1115.     int ch;
  1116.     unsigned cnt;
  1117.  
  1118.     limit = (w*b)/8;
  1119.     i = 0;
  1120.     /* set the line to white */
  1121.     memset(s, 0xff, limit+1); 
  1122.  
  1123.     if (rle_dy) {
  1124.         rle_dy--;
  1125.         return;
  1126.     }
  1127.  
  1128.     if (rle_dx) {
  1129.         for ( ; rle_dx > 0; rle_dx--) {
  1130.         s++;
  1131.         i++;
  1132.         }
  1133.     }
  1134.  
  1135.     while (i<=limit) {
  1136.         cnt = fgetc(f);
  1137.         ch  = fgetc(f);
  1138.         if (cnt == 0) { /* special operation */
  1139.         switch(ch) {
  1140.             case 0:    /* EOL */
  1141.             return;    /* this is our way out */
  1142.             case 1:    /* End of Bitmap */
  1143.             return;
  1144.             case 2:    /* Delta */  /* untested */
  1145.             rle_dx = fgetc(f) + i;
  1146.             rle_dy = fgetc(f);
  1147.             return;
  1148.             default:    /* next cnt bytes are absolute */
  1149.             for (cnt = ch; cnt>0 && i<=limit; cnt--) {
  1150.                     i++;
  1151.                 *s++ = fgetc(f);
  1152.                 }
  1153.             if (ch % 2)    /* word align file */
  1154.                 (void)fgetc(f);
  1155.         }
  1156.         }
  1157.         else { /* cnt is repeat count */
  1158.         for ( ; cnt>0 && i<=limit; cnt--) {
  1159.             i++;
  1160.             *s++ = ch;
  1161.         }
  1162.         }
  1163.     }
  1164. }
  1165.  
  1166. void bmpgraph(f,filename,emwidth,emheight)
  1167. FILE *f;
  1168. char filename[];
  1169. float emwidth, emheight;    /* dimension in pixels */
  1170. {
  1171.     struct bitmapfileheader bmfh;
  1172.     struct bitmapinfoheader bmih;
  1173.  
  1174.     unsigned char isblack[256];
  1175.     unsigned char rr;
  1176.     unsigned char gg;
  1177.     unsigned char bb;
  1178.     unsigned char c = 0;
  1179.  
  1180.     char *line;
  1181.     char *pshexa;
  1182.  
  1183.     int clrtablesize;
  1184.     int i;
  1185.     int j;
  1186.  
  1187.     unsigned char omask;
  1188.     int oroll;
  1189.  
  1190.     unsigned char emask = 0;
  1191.     integer ewidth = 0;
  1192.     int isOS2;
  1193.  
  1194.         /* read the header of the file */
  1195.     fread(bmfh.type, 1, 2, f);
  1196.     bmfh.size = readinteger(f);
  1197.     bmfh.reserved1 = readhalfword(f);
  1198.     bmfh.reserved2 = readhalfword(f);
  1199.     bmfh.offbits = readinteger(f);
  1200.     if (feof(f)) {
  1201.         sprintf(errbuf, "em:graph: Unable to Read Valid BMP Header\n");
  1202.         specerror(errbuf);
  1203.         return;
  1204.     }
  1205.  
  1206.     bmih.size = readinteger(f);
  1207.     if (bmih.size == 12) { /* OS2 bitmap */
  1208.         isOS2 = TRUE;    
  1209.         bmih.width = readhalfword(f);
  1210.         bmih.height = readhalfword(f);
  1211.         bmih.planes = readhalfword(f);
  1212.         bmih.bitcount = readhalfword(f);
  1213.         /* the following don't exist in OS2 format so fill with 0's */
  1214.         bmih.compression = RGB;
  1215.         bmih.sizeimage = 0;
  1216.         bmih.xpelspermeter = 0;
  1217.         bmih.ypelspermeter = 0;
  1218.         bmih.clrused = 0;
  1219.         bmih.clrimportant = 0;
  1220.     }
  1221.     else { /* Windows bitmap */
  1222.         isOS2 = FALSE;    
  1223.         bmih.width = readinteger(f);
  1224.         bmih.height = readinteger(f);
  1225.         bmih.planes = readhalfword(f);
  1226.         bmih.bitcount = readhalfword(f);
  1227.         bmih.compression = readinteger(f);
  1228.         bmih.sizeimage = readinteger(f);
  1229.         bmih.xpelspermeter = readinteger(f);
  1230.         bmih.ypelspermeter = readinteger(f);
  1231.         bmih.clrused = readinteger(f);
  1232.         bmih.clrimportant = readinteger(f);
  1233.     }
  1234.  
  1235.     if (feof(f)) {
  1236.         sprintf(errbuf, "em:graph: Unable to Read Valid BMP Info");
  1237.         specerror(errbuf);
  1238.         return;
  1239.     }
  1240.  
  1241.     if (memcmp(bmfh.type, "BM", 2)) {
  1242.         sprintf(errbuf, "em:graph: Unknown BMP File Type");
  1243.         specerror(errbuf);
  1244.         return;
  1245.     }
  1246.  
  1247.     if ((bmih.compression == RLE4) && (bmih.bitcount != 4)) {
  1248.         sprintf(errbuf, "em:graph: Can't do BMP RLE4 with %d bits per pixel",
  1249.             bmih.bitcount);
  1250.         specerror(errbuf);
  1251.         return;
  1252.     }
  1253.  
  1254.     if ((bmih.compression == RLE8) && (bmih.bitcount != 8)) {
  1255.         sprintf(errbuf, "em:graph: Can't do BMP RLE8 with %d bits per pixel\n",
  1256.             bmih.bitcount);
  1257.         specerror(errbuf);
  1258.         return;
  1259.     }
  1260.  
  1261.     imagehead(filename,(int)bmih.width,(int)bmih.height,emwidth,emheight);
  1262.  
  1263.     /* determine the size of the color table to read */
  1264.     clrtablesize = 0;
  1265.     if (bmih.clrused == 0) {
  1266.         switch (bmih.bitcount) {
  1267.             case 1:
  1268.                 clrtablesize = 2;
  1269.                 break;
  1270.             case 4:
  1271.                 clrtablesize = 16;
  1272.                 break;
  1273.             case 8:
  1274.                 clrtablesize = 256;
  1275.                 break;
  1276.             case 24:
  1277.                 break;
  1278.         }
  1279.     }
  1280.         else
  1281.         clrtablesize = bmih.clrused;
  1282.  
  1283.     /* read in the color table */
  1284.     for (i = 0; i < clrtablesize; i++) {
  1285.         bb = fgetc(f);
  1286.         gg = fgetc(f);
  1287.         rr = fgetc(f);
  1288.         isblack[i] = (rr < 0xff) || (gg < 0xff) || (bb < 0xff);
  1289.         if (!isOS2)
  1290.             (void) fgetc(f);
  1291.     }
  1292.  
  1293.     line = (char *) mymalloc((integer)((bmih.width * bmih.bitcount) / 8) + 1);
  1294.     pshexa = (char *) mymalloc((integer)tobyte(bmih.width));
  1295.  
  1296.     /* output the postscript image size preamble */
  1297.     cmdout("/picstr");
  1298.     numout((integer)tobyte(bmih.width));
  1299.     cmdout("string def");
  1300.  
  1301.     numout((integer)bmih.width);
  1302.     numout((integer)bmih.height);
  1303.     numout((integer)1);
  1304.  
  1305.     cmdout("[");
  1306.     numout((integer)bmih.width);
  1307.     numout((integer)0);
  1308.     numout((integer)0);
  1309.     numout((integer)bmih.height);
  1310.     numout((integer)0);
  1311.     numout((integer)bmih.height);
  1312.     cmdout("]");
  1313.  
  1314.     nlcmdout("{currentfile picstr readhexstring pop} image");
  1315.  
  1316.     if (bmih.bitcount == 1) {
  1317.         if (bmih.width%8)
  1318.             emask = (1<<(8-(bmih.width%8)))-1;    /* mask for edge of bitmap */
  1319.         else
  1320.             emask = 0;
  1321.         ewidth = tobyte(bmih.width);
  1322.     }
  1323.  
  1324.     /* read in all the lines of the file */
  1325.     for (i = 0; i < bmih.height; i++) {
  1326.         memset(pshexa,0xff,tobyte(bmih.width));
  1327.         switch (bmih.compression) {
  1328.             case RGB:
  1329.             rgbread(f, (int) bmih.width, (int) bmih.bitcount, line);
  1330.             break;
  1331.             case RLE4:
  1332.             rle4read(f, (int) bmih.width, (int) bmih.bitcount, line);
  1333.             break;
  1334.             case RLE8:
  1335.             rle8read(f, (int) bmih.width, (int) bmih.bitcount, line);
  1336.             break;
  1337.             default:
  1338.             sprintf(errbuf,"em:graph: Unknown BMP compression\n");
  1339.             specerror(errbuf);
  1340.             return;
  1341.         }
  1342.  
  1343.         omask = 0x80;
  1344.         oroll = 7;
  1345.  
  1346.         if (bmih.bitcount == 1) {
  1347.             if (isblack[0])
  1348.             for (j = 0; j < ewidth ; j++)
  1349.                 pshexa[j] = line[j];
  1350.             else
  1351.             for (j = 0; j < ewidth ; j++)
  1352.                 pshexa[j] = ~line[j];
  1353.             pshexa[ewidth-1] |= emask;
  1354.         }
  1355.         else {
  1356.             for (j = 0; j < bmih.width; j++) {
  1357.             switch (bmih.bitcount) {
  1358.                 case 4:
  1359.                     c = line[j>>1];
  1360.                     if (!(j&1))
  1361.                         c >>= 4;
  1362.                     c = isblack[ c & 0x0f ];
  1363.                     break;
  1364.                 case 8:
  1365.                     c = isblack[ (int)(line[j]) ];
  1366.                     break;
  1367.                 case 24:
  1368.                     rr = line[j*3];
  1369.                     gg = line[j*3+1];
  1370.                     bb = line[j*3+2];
  1371.                     c = (rr < 0xff) || (gg < 0xff) || (bb < 0xff);
  1372.                     break;
  1373.             }
  1374.             if (c) 
  1375.                 pshexa[j/8] &= ~omask;
  1376.             else
  1377.                 pshexa[j/8] |= omask;
  1378.             oroll--;
  1379.             omask >>= 1;
  1380.             if (oroll < 0) {
  1381.                 omask = 0x80;
  1382.                 oroll = 7;
  1383.             }
  1384.             }
  1385.         }
  1386.         newline();
  1387.         mhexout(pshexa,(long)tobyte(bmih.width));
  1388.     }
  1389.     imagetail() ;
  1390.     free(pshexa);
  1391.     free(line);
  1392. }
  1393. /* ------------------------------------------------------------------------ */
  1394.  
  1395. #define PCX 0
  1396. #define MSP 1
  1397. #define BMP 2
  1398. char *extarr[]=
  1399. { ".pcx", ".msp", ".bmp", NULL };
  1400.  
  1401. void emgraph(filename,emwidth,emheight)
  1402. char filename[];
  1403. float emwidth, emheight;    /* dimension in pixels */
  1404. {
  1405.     char fname[80];
  1406.     int filetype;
  1407.     FILE *f;
  1408.     char *env;
  1409.     char id[4];
  1410.     int i;
  1411.  
  1412.     strcpy(fname, filename);
  1413.  
  1414.     /* find the file */
  1415.     f = search(figpath, fname, READBIN);
  1416.     if (f == (FILE *)NULL) {
  1417.            if ( (env = getenv("DVIDRVGRAPH")) != NULL )
  1418.         f = search(env,filename,READBIN);
  1419.     }
  1420.     /* if still haven't found it try adding extensions */
  1421.     if (f == (FILE *)NULL) {
  1422.         i = 0;
  1423.         while (extarr[i] != NULL) {
  1424.         strcpy(fname, filename);
  1425.         strcat(fname, extarr[i]);
  1426.         f = search(figpath, fname, READBIN);
  1427.         if (f == (FILE *)NULL) {
  1428.                 if ( (env = getenv("DVIDRVGRAPH")) != NULL )
  1429.             f = search(env,filename,READBIN);
  1430.         }
  1431.         if (f != (FILE *)NULL)
  1432.             break;
  1433.         i++;
  1434.         }
  1435.     }
  1436.  
  1437.     filetype = -1;
  1438.     if (f != (FILE *)NULL) {
  1439.         for (i=0; i<4; i++) {
  1440.         id[i] = readquarterword(f);
  1441.         }
  1442.         if ( (id[0] == 0x0a) && (id[2] == 0x01) )
  1443.         filetype = PCX;
  1444.         if (!memcmp(id, "DanM", 4))
  1445.         filetype = MSP;
  1446.         if (!memcmp(id, "LinS", 4))
  1447.         filetype = MSP;
  1448.         if (!memcmp(id, "BM", 2))
  1449.         filetype = BMP;
  1450.         fseek(f, 0L, SEEK_SET);
  1451.     }
  1452.  
  1453.     switch (filetype) {
  1454.         case PCX:
  1455.             pcxgraph(f, fname, emwidth, emheight);
  1456.             break;
  1457.         case MSP:
  1458.             mspgraph(f, fname, emwidth, emheight);
  1459.             break;
  1460.         case BMP:
  1461.             bmpgraph(f, fname, emwidth, emheight);
  1462.             break;
  1463.         default:
  1464.             sprintf(fname,"em:graph: %s: File not found", filename);
  1465.             error(fname);
  1466.     }
  1467.     if (f != (FILE *)NULL)
  1468.         fclose(f);
  1469. }
  1470.  
  1471. #else
  1472. void emspecial(p)
  1473. char *p ;
  1474. {
  1475.     sprintf(errbuf,"emTeX specials not compiled in this version");
  1476.     specerror(errbuf);
  1477. }
  1478. #endif /* EMTEX */
  1479.